#ifndef __PLATFORM_OACTION_H__
#define __PLATFORM_OACTION_H__

class oModel;
class oEffect;
class oBody;

namespace platform
{
	class oUnit;
	class oAction;
	class oBullet;
	typedef delegate<void (oAction* action)> oActionHandler;
	typedef delegate<void (oUnit* source, oUnit* target, float damage)> oDamageHandler;

	class oDLL oAction
	{
	public:
		oAction(int id, int priority, oUnit* owner);
		virtual ~oAction();
		float reaction;
		int getId() const;
		int getPriority() const;
		bool isDoing() const;
		oUnit* getOwner() const;
		oActionHandler actionStart;
		oActionHandler actionEnd;
		virtual bool isAvailable();
		virtual void run();
		virtual void update(ccTime dt);
		virtual void stop();
		static oAction* create(int id, oUnit* unit);
	protected:
		oUnit* _owner;
	private:
		bool _isDoing;
		int _id;
		int _priority;
		float _reflexDelta;
	};

	struct oDLL oID
	{
		static const string AnimationWalk;
		static const string AnimationAttack;
		static const string AnimationIdle;
		static const string AnimationJump;
		static const string AnimationHit;
		static const string AnimationDie;

		static const int ActionWalk;
		static const int ActionTurn;
		static const int ActionMeleeAttack;
		static const int ActionRangeAttack;
		static const int ActionIdle;
		static const int ActionStop;
		static const int ActionJump;
		static const int ActionHit;
		static const int ActionDie;
		static const int ActionUser;

		static const int PriorityWalk;
		static const int PriorityTurn;
		static const int PriorityJump;
		static const int PriorityAttack;
		static const int PriorityIdle;
		static const int PriorityStop;
		static const int PriorityHit;
		static const int PriorityDie;

		static const float ReactionWalk;
		static const float ReactionIdle;
		static const float ReactionJump;

		static const string LookHappy;
		static const string LookFight;
		static const string LookSad;
		static const string LookDead;
	};

	class oDLL oWalk: public oAction
	{
	public:
		oWalk(oUnit* unit);
		virtual bool isAvailable();
		virtual void run();
		virtual void update(ccTime dt);
		virtual void stop();
		static oAction* create(oUnit* unit);
	};

	class oDLL oTurn: public oAction
	{
	public:
		oTurn(oUnit* unit);
		virtual void run();
		static oAction* create(oUnit* unit);
	};

	class oDLL oAttack: public oAction
	{
	public:
		oAttack(int id, oUnit* unit);
		virtual ~oAttack();
		virtual void run();
		virtual void update(ccTime dt);
		virtual void stop();
		void onAnimationEnd(oModel* model, uint32 index);
		float getDamage(oUnit* target);
		virtual void onAttack() = 0;
		oDamageHandler damaged;
		static bool usePreciseHit;
		static CCPoint getHitPoint(oBody* self, oBody* target, b2Shape* selfShape);
	protected:
		float _current;
		float _attackDelay;
		float _attackEffectDelay;
		int _attackAnimationIndex;
	};

	class oDLL oMeleeAttack: public oAttack
	{
	public:
		oMeleeAttack(oUnit* unit);
		static oAction* create(oUnit* unit);
	protected:
		virtual void onAttack();
		b2PolygonShape _polygon;
	};

	class oDLL oRangeAttack: public oAttack
	{
	public:
		oRangeAttack(oUnit* unit);
		static oAction* create(oUnit* unit);
		bool onHitTarget(oBullet* bullet, oUnit* target);
	protected:
		virtual void onAttack();
	};

	class oDLL oIdle: public oAction
	{
	public:
		oIdle(oUnit* unit);
		virtual ~oIdle();
		virtual void run();
		virtual void update(ccTime dt);
		virtual void stop();
		static oAction* create(oUnit* unit);
		void onAnimationEnd(oModel* model, uint32 index);
	private:
		float _current;
		int _jumpAnimationIndex;
	};

	class oDLL oJump: public oAction
	{
	public:
		oJump(oUnit* unit);
		virtual bool isAvailable();
		virtual void run();
		virtual void update(ccTime dt);
		virtual void stop();
		static oAction* create(oUnit* unit);
	private:
		float _current;
	};

	class oDLL oStop: public oAction
	{
	public:
		oStop(oUnit* unit);
		virtual void run();
		static oAction* create(oUnit* unit);
	};

	class oDLL oHit: public oAction
	{
	public:
		oHit(oUnit* unit);
		virtual ~oHit();
		virtual void run();
		virtual void update( ccTime dt );
		virtual void stop();
		void setHitInfo(const CCPoint& hitPoint, const CCPoint& attackPower, bool hitFromRight);
		void onAnimationEnd(oModel* model, uint32 index);
		static oAction* create(oUnit* unit);
	protected:
		bool _hitFromRight;
		oEffect* _effect;
		CCPoint _hitPoint;
		CCPoint _attackPower;
		int _hitAnimationIndex;
	};

	class oDLL oDie: public oAction
	{
	public:
		oDie(oUnit* unit);
		virtual ~oDie();
		virtual void run();
		virtual void update(ccTime dt);
		virtual void stop();
		static oAction* create(oUnit* unit);
		void onAnimationEnd(oModel* model, uint32 index);
	private:
		int _dieAnimationIndex;
	};

	class oActionHelper
	{
	public:
		typedef oAction* (*oActionFunc)(oUnit* unit);
		static oAction* create(int id, oUnit* unit);
	private:
		static const oActionFunc creates[];
		static const uint32 MAX_BASE_ACTION; 
	};
}

#endif
